package server;


import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;

import common.ClientInterface;
import common.PlayerEvent;
import common.ServerInterface;

public class ServerInterfaceImpl extends UnicastRemoteObject 
	implements ServerInterface, ClientUpdater {

	private static final long serialVersionUID = 1L;
	
	// map storing session id, client callback pairs
	Map<UUID, ClientInterface> clients = 
			new HashMap<UUID, ClientInterface>(GameController.MAX_PLAYERS);
	GameController controller;
	
	protected ServerInterfaceImpl() throws RemoteException {
		super();
		controller = new GameControllerImpl(this);
	}


	private boolean isCientAttached(UUID id) {
		return clients.containsKey(id);
	}


	public synchronized UUID attachClient(ClientInterface client, String playerName) {
		UUID id = UUID.randomUUID();
		

		System.out.println("attach new client: " + this.ref);
		System.out.println("  assign id: " + id);
		
		controller.clientAttached(id, playerName);
		clients.put(id, client);
		
		try {
			// do client initialization here
			client.setLevel( 0);
			updateClients();
			
		} catch (RemoteException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return id;
	}

	
	@Override
	public synchronized void detachClient(UUID id) {
		if (!isCientAttached(id))
			throw new IllegalArgumentException("this client is not attached");

		// deinitialize client here
		
		controller.clientDetached(id);
		
		clients.remove(id);
		
		System.out.println("detached client with id " + id);
		
		updateClients();
	}

	
	
	@Override
	public synchronized void playerEvent(UUID id, PlayerEvent event) {
		if (!isCientAttached(id))
			throw new IllegalStateException("this client is not attached");
		
		controller.playerEvent(id, event);
		
		//System.out.println("got player event: " + event.name());
		
		updateClients();
	}
	
	
	
	@Override
	public void updateClients() {
		//System.out.println("update clients: " + clients.size());
		
		Iterator<Entry<UUID, ClientInterface>> it = clients.entrySet().iterator();
		while ( it.hasNext() ) {
			Entry<UUID, ClientInterface> entry = it.next();
			
			try {
				entry.getValue().updateGame(controller.getGame());
			} catch (RemoteException e) {
				
				System.out.println("got a RemoteException for client with id " + entry.getKey());
				System.out.println("  error message: " + e.getLocalizedMessage());
				System.out.println("  detaching this client");

				UUID id = entry.getKey();
				controller.clientDetached(id);
				clients.remove(id);
				
				// reset iterator to notify all clients
				it = clients.entrySet().iterator();
			}
		}
		
			

	}


}
